package sicnu.cs.ich.activity.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import lombok.RequiredArgsConstructor;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import sicnu.cs.ich.activity.domain.ActivityLike;
import sicnu.cs.ich.activity.mapper.ActivityMapper;
import sicnu.cs.ich.activity.mapper.ActivityNumMapper;
import sicnu.cs.ich.activity.mapper.ActivityTimelineMapper;
import sicnu.cs.ich.activity.service.IActivityLikeService;
import sicnu.cs.ich.activity.service.IActivityService;
import sicnu.cs.ich.activity.service.ICommentService;
import sicnu.cs.ich.api.common.Constants;
import sicnu.cs.ich.api.common.ResultInfo;
import sicnu.cs.ich.api.domain.dto.ActivityDTO;
import sicnu.cs.ich.api.domain.dto.CallDTO;
import sicnu.cs.ich.api.domain.entity.*;
import sicnu.cs.ich.api.domain.form.ActivityForm;
import sicnu.cs.ich.api.domain.form.AddCallForm;
import sicnu.cs.ich.api.domain.form.PageParam;
import sicnu.cs.ich.api.domain.vo.ActivityDetailVO;
import sicnu.cs.ich.api.domain.vo.CommentVO;
import sicnu.cs.ich.common.exceptions.exception.ActivityConverseException;
import sicnu.cs.ich.common.exceptions.exception.ActivityStatusException;
import sicnu.cs.ich.common.exceptions.exception.ActivityTimeException;
import sicnu.cs.ich.common.util.ResultInfoUtil;
import sicnu.cs.ich.security.service.IUserService;

import java.util.*;

/**
 * @author 黎琦
 * @date 2021-11-26 14:33
 */
@Service
@RequiredArgsConstructor
public class ActivityServiceImpl implements IActivityService {
    private final ActivityMapper activityMapper;
    private final ActivityNumMapper activityNumMapper;
    private final ActivityTimelineMapper activityTimelineMapper;
    private final ICommentService commentService;
    private final IActivityLikeService activityLikeService;
    private final IUserService userService;

    @Override
    public PageInfo<ActivityDTO> getAllActivity(PageParam param) {
        PageHelper.startPage(param.getPageNum(), param.getPageSize());
        List<ActivityDTO> list = activityMapper.getAllActivity();
        return new PageInfo<>(list);
    }

    @Override
    public PageInfo<CallDTO> getAllCall(PageParam param) {
        PageHelper.startPage(param.getPageNum(), param.getPageSize());
        List<CallDTO> allCall = activityMapper.getAllCall();
        return new PageInfo<>(allCall);
    }

    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public Integer insert(AddCallForm addCallForm, Integer uid, Integer isCallUpon, ArrayList<ActivityImg> images) {
        //活动判断开始时间小于结束时间
        if (!addCallForm.getActivityStartTime().before(addCallForm.getActivityEndTime())) {
            throw new ActivityTimeException("活动开始时间要小于结束时间");
        }
        //号召判断开始时间小于结束时间
        if(isCallUpon==1){
            Date callCreateTime = new Date();
            if (addCallForm.getCallEndTime()==null){
                throw new ActivityTimeException("号召时间不能为空");
            }else if (!callCreateTime.before(addCallForm.getCallEndTime())){
                throw new ActivityTimeException("号召开始时间要小于结束时间");
            }
        }

        //插入号召或活动主表
        Activities activities = Activities.builder()
                .userId(uid)
                .name(addCallForm.getName())
                .isCallUpon(isCallUpon)
                .content(addCallForm.getContent())
                .activityStartTime(addCallForm.getActivityStartTime())
                .activityEndTime(addCallForm.getActivityEndTime())
                .callCreateTime(new Date())
                .callEndTime(addCallForm.getCallEndTime())
                .regionCode(addCallForm.getRegionCode())
                .regionDetail(addCallForm.getRegionDetail())
                .likeNum(0)
                .maxNum(addCallForm.getMaxNum())
                .minNum(addCallForm.getMinNum())
                .status(1)
                .imgUrl(addCallForm.getPublicImg())
                .isEnd(0)
                .build();
        activityMapper.insert(activities);

        //插入活动阶段表
        List<ActivityTimeline> timelines = addCallForm.getStages();
        if (timelines != null) {
            for (ActivityTimeline timeline : timelines) {
                timeline.setActivityId(activities.getId());
            }
            activityTimelineMapper.insertAll(timelines);
        }

        //插入活动点赞表（mongodb）
        ActivityLike activityLike = ActivityLike.builder()
                .aid(activities.getId())
                .commentNum(0L)
                .responseNum(0L)
                .build();
        activityLikeService.insert(activityLike);

        //插入活动图片表
        if(images != null&&images.size()!=0){
            for (ActivityImg img : images) {
                img.setActivityId(activities.getId());
            }
            activityMapper.insertActivityImg(images);
        }

        //插入活动人数表
        ActivityNum activityNum = ActivityNum.builder()
                .aid(activities.getId())
                .num(0)
                .build();
        activityNumMapper.insert(activityNum);
        return activities.getId();
    }


    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public ResultInfo<Void> participate(Integer activityId, Integer uid) {
        Activities activities = activityMapper.selectById(activityId);
        if (activities == null) {
            throw new NoSuchElementException("活动/号召不存在");
        }
        //判断是否失效
        if (activities.getStatus() != 1) {
            return ResultInfoUtil.buildError("活动或号召已失效");
        }else if (activities.getIsCallUpon()==0){
            // 如果是活动，处理活动报名已截止的情况
            if (activities.getIsEnd()==1){
                //已被定时处理了
                return ResultInfoUtil.buildError("活动报名已结束");
            }else if((new Date()).after(activities.getActivityEndTime())){
                //这里处理被定时处理漏掉的活动已结束的情况（待优化）
                activityMapper.updateIsEndById(activityId, 1);
                return ResultInfoUtil.buildError("活动已结束");
            }
        }

        //如果是号召，查询号召是否过期，将定时任务漏掉的检测出来（待优化）
        Date date = new Date();
        if (activities.getIsCallUpon()==1&&date.after(activities.getCallEndTime())) {
            //过期，即更新状态
            activityMapper.updateStatusById(activityId, 0);
            return ResultInfoUtil.buildError("号召已过期");
        }

        ActivityParticipate activityParticipate = ActivityParticipate.builder()
                .activityId(activityId)
                .userId(uid)
                //参与者待审核
                .status(0)
                .build();
        try {
            activityMapper.insertActivityParticipate(activityParticipate);
            activityNumMapper.updateNum(activityId);
            return ResultInfoUtil.buildSuccess("报名成功");
        } catch (DuplicateKeyException e) {
            throw new ActivityStatusException("重复参加活动");
        }
    }


    @Override
    public ActivityDetailVO getActivityDetail(Integer aid) {
        //先找活动详情
        Activities activities = activityMapper.selectById(aid);
        if(activities==null){
            throw new NoSuchElementException("没有找到活动");
        }
        //活动参加人数/号召响应人数
        ActivityNum activityNum = activityNumMapper.selectById(aid);

        //活动发起人信息
        var userInfo = userService.findUserInfo(activities.getUserId());
        // 计算年龄

        //时间线
        List<ActivityTimeline> timelines = activityTimelineMapper.selectList(new QueryWrapper<ActivityTimeline>().eq("activity_id", aid));
        //评论信息
        List<CommentVO> commentVOList = commentService.getCommentByAid(aid);
        return ActivityDetailVO.builder()
                .activities(activities)
                .activityNum(activityNum)
                .userInfo(userInfo)
                .timelines(timelines)
                .comments(commentVOList)
                .build();
    }

    @Override
    public void callToActivity(Integer aid) {
//        检测是否满足条件，即人数是否达标
        Activities activities = activityMapper.selectById(aid);
        ActivityNum activityNum = activityNumMapper.selectById(aid);
        if (activities.getMinNum()>activityNum.getNum()){
            throw new ActivityConverseException("号召人数未达标，还差"+(activities.getMinNum()-activityNum.getNum())+"人");
        }
//        activityMapper.updateIsCallUponById(aid, 0);
        //转换后，将活动的参加人数置为0
//        activityNumMapper.updateNumByAid(aid, 0);
    }

    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public void updateInfo(ActivityForm activityForm, ArrayList<ActivityImg> images) {
        //更新活动主表信息
        //转换为号召待转换状态
        Activities activities = activityForm.getActivities();
        activities.setIsCallUpon(0);
        Date date = new Date();
        activities.setActivityCreateTime(date);
        activityMapper.updateInfo(activities);
        //更新活动阶段信息
        //先删除
        activityTimelineMapper.deleteByAid(activityForm.getActivities().getId());
        List<ActivityTimeline> stages = activityForm.getStages();
        //在添加
        for (ActivityTimeline timeline : stages) {
            timeline.setActivityId(activities.getId());
        }
        activityTimelineMapper.insertAll(stages);
    }

    @Override
    public void stopApply(Integer aid) {
        activityMapper.updateIsEndById(aid, 1);
    }

    @Override
    public void scheduledOfActivityStop() {
        activityMapper.updateAllActivityIsEnd();
    }

    @Override
    public void scheduledOfCallStop() {
        activityMapper.updateAllCalStatus();
    }

    @Override
    public void scheduledOfCallOk() {
        activityMapper.updateAllIsCallUpon();
    }

    @Override
    public Map<Integer, Long> allActivityParticipantNum() {
        List<ActivityNum> activityNums = activityNumMapper.selectList(null);
        Map<Integer, Long> map = new HashMap<>(Constants.ACTIVITY_INIT_NUM);
        for (ActivityNum activityNum : activityNums) {
            int num = activityNum.getNum();
            map.put(activityNum.getAid(), (long) num);
        }
        return map;
    }
}
